package main

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
)

// *************************************************************
// 返回值写在后面，可以返回多个值，go语言是函数编程语言，函数是一等公民可以当变量，参数，返回值都可以是函数
// go语言中没有默认参数，可选参数，函数重载等特性
// *************************************************************

// 有个可变参数,即sum可以传递无数个整数 最后循环求出和
func sum(num ...int) int {
	s := 0
	for i := range num {
		s += num[i]
	}
	return s
}

// 使用函数式编程实现div的功能
// go语言的名字在前类型在后的形式很容易定义一下的复合函数
func apply(op func(int, int) int, a, b int) int {
	p := reflect.ValueOf(op).Pointer()    //通过反射获取函数的指针
	opName := runtime.FuncForPC(p).Name() // 获取该函数指针运行时的函数名称
	fmt.Printf("calling function %s with args"+"(%d,%d)\n", opName, a, b)
	return op(a, b)
}

// 函数直接返回多个值
func div1(a, b int) (int, int) {
	return a / b, a % b
}

// 函数可以返回多个值 如果声明了函数名称的话可以直接return
func div(a, b int) (q, r int) {
	q = a / b
	r = a % b
	return
}

// 重写pow函数
func pow(a, b int) int {
	return int(math.Pow(float64(a), float64(b)))
}

type sub func(a, b int) int // 定义一个函数类型
func subTest(a, b int) int {
	return a - b
}

func main() {
	q, r := div(13, 3)
	fmt.Println(q, r)
	fmt.Println(apply(pow, 13, 3)) // 直接把函数传进去
	fmt.Println(apply(func(a, b int) int {
		return int(math.Pow(float64(a), float64(b)))
	}, 13, 3)) // 直接写匿名函数 go中没有 花哨的Lambda表达式
	var mySub sub = subTest // 因为上面定义的函数 subTest的参数形式和 sub函数类型一致 所以可以进行赋值
	fmt.Println(mySub(1, 2))

}
